More time fixes. Now time is set properly in domU's, and
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 11 Aug 2005 13:07:08 +0000 (13:07 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 11 Aug 2005 13:07:08 +0000 (13:07 +0000)
settimeofday() is simplified and fixed.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
xen/arch/x86/domain.c
xen/arch/x86/domain_build.c
xen/arch/x86/time.c

index 4e30c2ec83f83dbe4beb9a114e994d388cfa2073..6b2fe1ccc55822b993ccf52dd2eda5d70c00198a 100644 (file)
@@ -227,33 +227,20 @@ static unsigned long get_usec_offset(struct shadow_time_info *shadow)
        return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
 }
 
-static void update_wallclock(void)
+static void __update_wallclock(time_t sec, long nsec)
 {
-       shared_info_t *s = HYPERVISOR_shared_info;
        long wtm_nsec, xtime_nsec;
        time_t wtm_sec, xtime_sec;
-       u64 tmp, nsec;
-
-       do {
-               shadow_tv_version = s->wc_version;
-               rmb();
-               shadow_tv.tv_sec  = s->wc_sec;
-               shadow_tv.tv_nsec = s->wc_nsec;
-               rmb();
-       }
-       while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
-
-       if (independent_wallclock)
-               return;
+       u64 tmp, wc_nsec;
 
        /* Adjust wall-clock time base based on wall_jiffies ticks. */
-       nsec = processed_system_time;
-       nsec += (u64)shadow_tv.tv_sec * 1000000000ULL;
-       nsec += (u64)shadow_tv.tv_nsec;
-       nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
+       wc_nsec = processed_system_time;
+       wc_nsec += (u64)sec * 1000000000ULL;
+       wc_nsec += (u64)nsec;
+       wc_nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
 
        /* Split wallclock base into seconds and nanoseconds. */
-       tmp = nsec;
+       tmp = wc_nsec;
        xtime_nsec = do_div(tmp, 1000000000);
        xtime_sec  = (time_t)tmp;
 
@@ -262,6 +249,28 @@ static void update_wallclock(void)
 
        set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+       time_adjust = 0;                /* stop active adjtime() */
+       time_status |= STA_UNSYNC;
+       time_maxerror = NTP_PHASE_LIMIT;
+       time_esterror = NTP_PHASE_LIMIT;
+}
+
+static void update_wallclock(void)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+
+       do {
+               shadow_tv_version = s->wc_version;
+               rmb();
+               shadow_tv.tv_sec  = s->wc_sec;
+               shadow_tv.tv_nsec = s->wc_nsec;
+               rmb();
+       }
+       while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
+
+       if (!independent_wallclock)
+               __update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec);
 }
 
 /*
@@ -408,19 +417,15 @@ EXPORT_SYMBOL(do_gettimeofday);
 
 int do_settimeofday(struct timespec *tv)
 {
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec;
+       time_t sec;
        s64 nsec;
-       struct timespec xentime;
        unsigned int cpu;
        struct shadow_time_info *shadow;
+       dom0_op_t op;
 
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       if (!independent_wallclock && !(xen_start_info.flags & SIF_INITDOMAIN))
-               return 0; /* Silent failure? */
-
        cpu = get_cpu();
        shadow = &per_cpu(shadow_time, cpu);
 
@@ -431,51 +436,30 @@ int do_settimeofday(struct timespec *tv)
         * overflows. If that were to happen then our shadow time values would
         * be stale, so we can retry with fresh ones.
         */
- again:
-       nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
-       if (unlikely(!time_values_up_to_date(cpu))) {
+       for ( ; ; ) {
+               nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
+               if (time_values_up_to_date(cpu))
+                       break;
                get_time_values_from_xen();
-               goto again;
        }
-
+       sec = tv->tv_sec;
        __normalize_time(&sec, &nsec);
-       set_normalized_timespec(&xentime, sec, nsec);
-
-       /*
-        * This is revolting. We need to set "xtime" correctly. However, the
-        * value in this location is the value at the most recent update of
-        * wall time.  Discover what correction gettimeofday() would have
-        * made, and then undo it!
-        */
-       nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
-
-       nsec -= (shadow->system_timestamp - processed_system_time);
-
-       __normalize_time(&sec, &nsec);
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-       time_adjust = 0;                /* stop active adjtime() */
-       time_status |= STA_UNSYNC;
-       time_maxerror = NTP_PHASE_LIMIT;
-       time_esterror = NTP_PHASE_LIMIT;
-
-#ifdef CONFIG_XEN_PRIVILEGED_GUEST
        if ((xen_start_info.flags & SIF_INITDOMAIN) &&
            !independent_wallclock) {
-               dom0_op_t op;
                op.cmd = DOM0_SETTIME;
-               op.u.settime.secs        = xentime.tv_sec;
-               op.u.settime.nsecs       = xentime.tv_nsec;
+               op.u.settime.secs        = sec;
+               op.u.settime.nsecs       = nsec;
                op.u.settime.system_time = shadow->system_timestamp;
-               write_sequnlock_irq(&xtime_lock);
                HYPERVISOR_dom0_op(&op);
-       } else
-#endif
-               write_sequnlock_irq(&xtime_lock);
+               update_wallclock();
+       } else if (independent_wallclock) {
+               nsec -= shadow->system_timestamp;
+               __normalize_time(&sec, &nsec);
+               __update_wallclock(sec, nsec);
+       }
+
+       write_sequnlock_irq(&xtime_lock);
 
        put_cpu();
 
@@ -492,6 +476,9 @@ static int set_rtc_mmss(unsigned long nowtime)
 
        WARN_ON(irqs_disabled());
 
+       if (!(xen_start_info.flags & SIF_INITDOMAIN))
+               return 0;
+
        /* gets recalled with irq locally disabled */
        spin_lock_irq(&rtc_lock);
        if (efi_enabled)
@@ -603,8 +590,10 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
                profile_tick(CPU_PROFILING, regs);
        }
 
-       if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version))
+       if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
                update_wallclock();
+               clock_was_set();
+       }
 }
 
 /*
index dedebbbd6c9b54937f1c1e70f2d1ece769861c1c..efd967464d1ca337b4fb4fafd98555a93f29834d 100644 (file)
@@ -279,8 +279,6 @@ void arch_do_createdomain(struct vcpu *v)
     
     shadow_lock_init(d);        
     INIT_LIST_HEAD(&d->arch.free_shadow_frames);
-
-    init_domain_time(d);
 }
 
 void arch_do_boot_vcpu(struct vcpu *v)
@@ -481,7 +479,10 @@ int arch_set_info_guest(
     }
 
     update_pagetables(v);
-    
+
+    if ( v->vcpu_id == 0 )
+        init_domain_time(d);
+
     /* Don't redo final setup */
     set_bit(_VCPUF_initialised, &v->vcpu_flags);
 
index 9ba5b4512bfba8f07f32091021fe9fd83463ed72..b9941763c4807ee07769e02456084e830a0f5acc 100644 (file)
@@ -618,6 +618,8 @@ int construct_dom0(struct domain *d,
     /* DOM0 gets access to everything. */
     physdev_init_dom0(d);
 
+    init_domain_time(d);
+
     set_bit(_DOMF_constructed, &d->domain_flags);
 
     new_thread(v, dsi.v_kernentry, vstack_end, vstartinfo_start);
index d978c8170ec9e03b004f55a76640c7eee5fbc2db..81100e7a1cf9c1c274470950e173a16db75d290c 100644 (file)
@@ -44,6 +44,7 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 int timer_ack = 0;
 unsigned long volatile jiffies;
 static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */
+static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED;
 
 struct time_scale {
     int shift;
@@ -699,13 +700,14 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
     struct domain *d;
     shared_info_t *s;
 
-    x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base;
+    x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
     y = do_div(x, 1000000000);
 
     wc_sec  = _wc_sec  = (u32)x;
     wc_nsec = _wc_nsec = (u32)y;
 
     read_lock(&domlist_lock);
+    spin_lock(&wc_lock);
 
     for_each_domain ( d )
     {
@@ -716,15 +718,18 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
         version_update_end(&s->wc_version);
     }
 
+    spin_unlock(&wc_lock);
     read_unlock(&domlist_lock);
 }
 
 void init_domain_time(struct domain *d)
 {
+    spin_lock(&wc_lock);
     version_update_begin(&d->shared_info->wc_version);
     d->shared_info->wc_sec  = wc_sec;
     d->shared_info->wc_nsec = wc_nsec;
     version_update_end(&d->shared_info->wc_version);
+    spin_unlock(&wc_lock);
 }
 
 static void local_time_calibration(void *unused)